home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / sat / msat09.tgz / XPB.C < prev    next >
Text File  |  1994-09-17  |  40KB  |  1,757 lines

  1. /*
  2.  *   Copyright 1992, 1993, 1994 John Melton (G0ORX/N6LYT)
  3.  *              All Rights Reserved
  4.  *
  5.  *   This program is free software; you can redistribute it and/or modify
  6.  *   it under the terms of the GNU General Public License as published by
  7.  *   the Free Software Foundation; either version 1, or (at your option)
  8.  *   any later version.
  9.  *
  10.  *   This program is distributed in the hope that it will be useful,
  11.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *   GNU General Public License for more details.
  14.  *
  15.  *   You should have received a copy of the GNU General Public License
  16.  *   along with this program; if not, write to the Free Software
  17.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20.  
  21. /*
  22.     xpb.c
  23.  
  24.     eXperimental Pacsat Broadcast Protocal Receiver
  25.      -           -      -
  26.  
  27.     This software was written to provide a receive only capability
  28.     for collecting files and directories from satellites running
  29.     the Pacsat Protocols running on the Linux Operating System.
  30.  
  31.     This program has been run using the 1.0 version of the
  32.     Linux kernel with the patches from Alan Cox to provide AX.25
  33.     encapsulation of SLIP.
  34.  
  35.     The TNC must be setup for KISS.
  36.  
  37.     John Melton
  38.     G0ORX, N6LYT
  39.  
  40.     4 Charlwoods Close
  41.     Copthorne
  42.     West Sussex
  43.     RH10 3QZ
  44.     England
  45.  
  46.     INTERNET:    g0orx@amsat.org
  47.             n6lyt@amsat.org
  48.             john@images.demon.co.uk
  49.             J.D.Melton@slh0613.icl.wins.co.uk
  50.  
  51.     History:
  52.     -------
  53.  
  54.     0.1    Initial version - no GUI interface.        G0ORX
  55.     0.2    Added X-Windows (OpenView) interface.        G0ORX
  56.     0.3    Added transmit capability for file and hole fill requests.
  57.     0.4    Added ability to receive fragmented file headers for directory
  58.         broadcasts,  and assemble them together (most headers are
  59.         less than the 244 byte packet limit, but some people have
  60.         set their limit to 128,  which causes the headers to be
  61.         fragmented).                    G0ORX
  62.     0.5    Reworked hole lists.                G0ORX
  63.     0.6    Changed to Xaw widgets.                G4KLX
  64.         Added automatic file and directory requests.
  65.     0.7    Added cancel fill.                G4KLX
  66.         Added TLM logging.
  67.     0.8    Added directory hole list pruning.        G4KLX
  68.         Added directory entry duplicate checking.
  69.         Added flushing of directory hole file every
  70.         30 seconds.
  71.         Added KISS logging.
  72. */
  73.  
  74. #define VERSION_STRING "(version 0.8 by g0orx/n6lyt/g4klx)"
  75.  
  76. #include <X11/Intrinsic.h>
  77. #include <X11/StringDefs.h>
  78. #include <X11/Shell.h>
  79. #include <X11/Xaw/Cardinals.h>
  80. #include <X11/Xaw/Form.h>
  81. #include <X11/Xaw/Text.h>
  82. #include <X11/Xaw/AsciiText.h>
  83. #include <X11/Xaw/Label.h>
  84. #include <X11/Xaw/Command.h>
  85.  
  86. #include <sys/types.h>
  87. #include <sys/stat.h>
  88. #include <sys/socket.h>
  89.  
  90. #include <netinet/in.h>
  91. #include <linux/ax25.h>
  92.  
  93. #include <fcntl.h>
  94. #include <unistd.h>
  95. #include <stdio.h>
  96. #include <stdlib.h>
  97. #include <signal.h>
  98. #include <ctype.h>
  99. #include <time.h>
  100.  
  101. #include "xawutils.h"
  102. #include "ftl0.h"
  103. #include "xpb.h"
  104. #include "header.h"
  105. #include "request.h"
  106. #include "crc.h"
  107.  
  108. Display *dpy;
  109.  
  110. XtAppContext app_context;
  111.  
  112. typedef struct
  113. {
  114.     XFontStruct *bold_font, *button_font, *text_font;
  115. }
  116. Resources;
  117.  
  118. Resources  resources;
  119.  
  120. Widget toplevel, compwindow, quitbutton, kissbutton, tlmbutton, cancelbutton,
  121.     dirbutton, filebutton, filetext, totallabel, dirlabel, filelabel,
  122.     tlmlabel, crclabel, datawindow;
  123.  
  124. XtResource resource_list[] =
  125. {
  126.     {"boldFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  127.         XtOffsetOf(Resources, bold_font), XtRString, XtDefaultFont},
  128.     {"buttonFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  129.         XtOffsetOf(Resources, button_font), XtRString, XtDefaultFont},
  130.     {"textFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  131.         XtOffsetOf(Resources, text_font), XtRString, XtDefaultFont}
  132. };
  133.  
  134. Arg shell_args[] =
  135. {
  136.     {XtNtitle,        (XtArgVal)NULL}
  137. };
  138.  
  139. Arg form_args[] =
  140. {
  141.     {XtNdefaultDistance,    (XtArgVal)0}
  142. };
  143.  
  144. Arg button_args[] =
  145. {
  146.     {XtNcallback,        (XtArgVal)NULL},
  147.     {XtNlabel,        (XtArgVal)NULL},
  148.     {XtNfromHoriz,        (XtArgVal)NULL},
  149.     {XtNfont,        (XtArgVal)NULL},
  150.     {XtNresize,        (XtArgVal)False},
  151.     {XtNvertDistance,    (XtArgVal)6},
  152.     {XtNhorizDistance,    (XtArgVal)8},
  153.     {XtNtop,        XtChainTop},
  154.     {XtNbottom,        XtChainTop},
  155.     {XtNleft,        XtChainLeft},
  156.     {XtNright,        XtChainLeft}
  157. };
  158.  
  159. Arg text_args[] =
  160. {
  161.     {XtNfromHoriz,        (XtArgVal)NULL},
  162.     {XtNfont,        (XtArgVal)NULL},
  163.     {XtNstring,        (XtArgVal)NULL},
  164.     {XtNbackground,        (XtArgVal)NULL},
  165.     {XtNlength,        (XtArgVal)8},
  166.     {XtNwidth,        (XtArgVal)80},
  167.     {XtNvertDistance,    (XtArgVal)6},
  168.     {XtNhorizDistance,    (XtArgVal)8},
  169.     {XtNtop,        XtChainTop},
  170.     {XtNbottom,        XtChainTop},
  171.     {XtNleft,        XtChainLeft},
  172.     {XtNright,        XtChainLeft},
  173.     {XtNeditType,        XawtextEdit},
  174.     {XtNtype,        XawAsciiString},
  175.     {XtNuseStringInPlace,    True}
  176. };
  177.  
  178. Arg label_args[] =
  179. {
  180.     {XtNfromVert,        (XtArgVal)NULL},
  181.     {XtNfromHoriz,        (XtArgVal)NULL},
  182.     {XtNfont,        (XtArgVal)NULL},
  183.     {XtNwidth,        (XtArgVal)130},
  184.     {XtNlabel,        (XtArgVal)""},
  185.     {XtNheight,        (XtArgVal)25},
  186.     {XtNvertDistance,    (XtArgVal)0},
  187.     {XtNhorizDistance,    (XtArgVal)5},
  188.     {XtNborderWidth,    (XtArgVal)0},
  189.     {XtNjustify,        XtJustifyLeft},
  190.     {XtNresize,        False},
  191.     {XtNtop,        XtChainTop},
  192.     {XtNbottom,        XtChainTop},
  193.     {XtNleft,        XtChainLeft},
  194.     {XtNright,        XtChainLeft}
  195. };
  196.  
  197. Arg window_args[] =
  198. {
  199.     {XtNfromVert,        (XtArgVal)NULL},
  200.     {XtNbackground,        (XtArgVal)NULL},
  201.     {XtNfont,        (XtArgVal)NULL},
  202.     {XtNcursor,        (XtArgVal)NULL},
  203.     {XtNwidth,        (XtArgVal)600},
  204.     {XtNheight,        (XtArgVal)150},
  205.     {XtNvertDistance,    (XtArgVal)0},
  206.     {XtNhorizDistance,    (XtArgVal)0},
  207.     {XtNtop,        XtChainTop},
  208.     {XtNbottom,        XtChainBottom},
  209.     {XtNleft,        XtChainLeft},
  210.     {XtNright,        XtChainRight},
  211.     {XtNeditType,        XawtextEdit},
  212.     {XtNtype,        XawAsciiString},
  213.     {XtNwrap,        XawtextWrapLine},
  214.     {XtNdisplayNonprinting,    False},
  215.     {XtNdisplayCaret,    False},
  216.     {XtNsensitive,        False}
  217. };
  218.  
  219. #define    REQUEST_NONE    0
  220. #define    REQUEST_DIR    1
  221. #define    REQUEST_FILE    2
  222.  
  223. int request_state = REQUEST_NONE;
  224.  
  225. #define    FILL_NONE    0
  226. #define    FILL_UNIQUE    1
  227. #define    FILL_OVERLAP    2
  228.  
  229. FILE *fptlm  = NULL;
  230. FILE *fpkiss = NULL;
  231.  
  232. char writebuf[200];
  233. char id[10];
  234.  
  235. char satelliteId[16];
  236. char myCall[16];
  237.  
  238. int s_raw;
  239. int s_file;
  240. int s_directory;
  241. struct sockaddr_ax25 dest;
  242. struct sockaddr_ax25 src;
  243.  
  244. struct sockaddr_in request_addr;
  245. int s_request;
  246.  
  247. #define    TIMEOUT        30
  248.  
  249. unsigned char buf[MAXBUFFER];
  250. int bufSize;
  251.  
  252.  
  253. OPENFILES of[MAXFILES + 1];    /* last entry is for the directory file */
  254. int nextof = 0;
  255.  
  256. unsigned long maxDays = 5;
  257.  
  258. int bytes     = 0;
  259. int fileBytes = 0;
  260. int dirBytes  = 0;
  261. int tlmBytes  = 0;
  262. int crcErrors = 0;
  263.  
  264. time_t start_time = 0;
  265. time_t end_time   = 0;
  266.  
  267. void FillDirectory(void);
  268. void FillFile(void);
  269. void CancelFill(void);
  270.  
  271. void writetext(char *text)
  272. {
  273.     XawTextPosition pos;
  274.     XawTextBlock tt;
  275.  
  276.     tt.firstPos = 0;
  277.     tt.ptr      = text;
  278.     tt.length   = strlen(text);
  279.     tt.format   = FMT8BIT;
  280.  
  281.     pos = XawTextGetInsertionPoint(datawindow);
  282.  
  283.     XawTextReplace(datawindow, pos, pos, &tt);
  284.  
  285.     pos += tt.length;
  286.     XawTextSetInsertionPoint(datawindow, pos);
  287. }
  288.  
  289. /*
  290.  *    Convert a call from the shifted ascii form used in an
  291.  *    AX.25 packet.
  292.  */
  293. int ConvertCall(char *c, char *call)
  294. {
  295.     char *ep = c + 6;
  296.     int ct = 0;
  297.  
  298.     while (ct < 6)
  299.     {
  300.         if (((*c >> 1) & 127) == ' ') break;
  301.  
  302.         *call = (*c >> 1) & 127;
  303.         call++;
  304.         ct++;
  305.         c++;
  306.     }
  307.     
  308.     if ((*ep & 0x1E) != 0)
  309.     {    
  310.         *call = '-';
  311.         call++;
  312.         call += sprintf(call, "%d", (int)(((*ep) >> 1) & 0x0F));
  313.     }
  314.  
  315.     *call = '\0';
  316.     
  317.     if (*ep & 1) return 0;
  318.  
  319.     return 1;
  320. }
  321.  
  322. /*
  323.  *    Convert a call to the shifted ascii form used in an
  324.  *    AX.25 packet.
  325.  */
  326. int MakeAddress(char *name, struct sockaddr_ax25 *sax)
  327. {
  328.     int ct = 0;
  329.     int ssid = 0;
  330.     char *p = name;
  331.  
  332.     while (ct < 6)
  333.     {
  334.         if (*p == '-' || *p == '\0') break;
  335.  
  336.         if (islower(*p)) *p = toupper(*p);
  337.  
  338.         if (!isalnum(*p))
  339.         {
  340.             printf("Invalid symbol in callsign %c\n", *p);
  341.             return -1;
  342.         }
  343.         
  344.         sax->sax25_call.ax25_call[ct] = (*p << 1);
  345.         p++;
  346.         ct++;
  347.     }
  348.  
  349.     while (ct < 6)
  350.     {
  351.         sax->sax25_call.ax25_call[ct] = ' ' << 1;
  352.         ct++;
  353.     }
  354.  
  355.     if (*p == '-')
  356.     {
  357.         p++;
  358.  
  359.         if (sscanf(p, "%d", &ssid) != 1 || ssid < 0 || ssid > 15)
  360.         {
  361.             printf("Invalid SSID - %s - %s\n", name, p);
  362.             return -1;
  363.         }
  364.     }
  365.  
  366.     sax->sax25_call.ax25_call[6]=((ssid + '0') << 1) & 0x1E;
  367.     sax->sax25_family = AF_AX25;
  368.  
  369.     return 0;
  370. }
  371.  
  372. void UpdateStatus(void)
  373. {
  374.     static int lastTotal = -1;
  375.     static int lastDir   = -1;
  376.     static int lastFile  = -1;
  377.     static int lastTLM   = -1;
  378.     static int lastCRC   = -1;
  379.     char label[30];
  380.     Arg args[1];
  381.  
  382.     if (bytes != lastTotal)
  383.     {
  384.         sprintf(label, "Total bytes %8d", bytes);
  385.         
  386.         XtSetArg(args[0], XtNlabel, label);
  387.         XtSetValues(totallabel, args, ONE);
  388.  
  389.         lastTotal = bytes;
  390.     }
  391.  
  392.     if (fileBytes != lastFile)
  393.     {
  394.         sprintf(label, "File bytes %7d", fileBytes);
  395.         
  396.         XtSetArg(args[0], XtNlabel, label);
  397.         XtSetValues(filelabel, args, ONE);
  398.  
  399.         lastFile = fileBytes;
  400.     }
  401.  
  402.     if (dirBytes != lastDir)
  403.     {
  404.         sprintf(label, "Dir bytes %7d", dirBytes);
  405.         
  406.         XtSetArg(args[0], XtNlabel, label);
  407.         XtSetValues(dirlabel, args, ONE);
  408.  
  409.         lastDir = dirBytes;
  410.     }
  411.  
  412.     if (tlmBytes != lastTLM)
  413.     {
  414.         sprintf(label, "TLM bytes %6d", tlmBytes);
  415.         
  416.         XtSetArg(args[0], XtNlabel, label);
  417.         XtSetValues(tlmlabel, args, ONE);
  418.  
  419.         lastTLM = tlmBytes;
  420.     }
  421.  
  422.     if (crcErrors != lastCRC)
  423.     {
  424.         sprintf(label, "CRC errors %3d", crcErrors);
  425.         
  426.         XtSetArg(args[0], XtNlabel, label);
  427.         XtSetValues(crclabel, args, ONE);
  428.  
  429.         lastCRC = crcErrors;
  430.     }
  431. }
  432.  
  433. /*
  434.  * Hole list maintenance
  435.  */
  436. int LoadHoleList(int f, char *holeName, char *fileName)
  437. {
  438.     FILE *holeFile;
  439.     FILE *fileFile;
  440.     HOLE *hole;
  441.     HOLE *prevHole;
  442.     int i;
  443.  
  444.     holeFile = fopen(holeName, "r");
  445.     fileFile = fopen(fileName, "r");
  446.  
  447.     /*
  448.      * handle the case where a .act file or a .hol file exist without
  449.      * the other. Usually caused by a crash.
  450.      */
  451.  
  452.     if (holeFile != NULL && fileFile != NULL)
  453.     {
  454.         fscanf(holeFile, "%d %*s %*s %*s", &of[f].hdrSeen);
  455.         fscanf(holeFile, "%d %*s %*s %*s", &of[f].fileSize);
  456.         fscanf(holeFile, "%d %*s", &of[f].holes);
  457.  
  458.         prevHole = NULL;
  459.  
  460.         for (i = 0; i < of[f].holes; i++)
  461.         {
  462.             hole           = (HOLE *)XtMalloc(sizeof(HOLE));
  463.             hole->nextHole = NULL;
  464.             fscanf(holeFile, "%u, %u", &hole->start, &hole->finish);
  465.  
  466.             if (prevHole == NULL)
  467.                 of[f].firstHole = hole;
  468.             else
  469.                 prevHole->nextHole = hole;
  470.  
  471.             prevHole = hole;
  472.         }
  473.     
  474.         fclose(holeFile);
  475.         fclose(fileFile);
  476.  
  477.         return(1);
  478.     }
  479.     else
  480.     {
  481.         if (fileFile != NULL) fclose(fileFile);
  482.         if (holeFile != NULL) fclose(holeFile);
  483.     
  484.         /* create an empty hole list */
  485.         of[f].firstHole           = (HOLE *)XtMalloc(sizeof(HOLE));
  486.         of[f].firstHole->start    = 0;
  487.         of[f].firstHole->finish   = 0xFFFFFFFF;
  488.         of[f].firstHole->nextHole = NULL;
  489.         of[f].holes               = 1;
  490.  
  491.         return(0);
  492.     }
  493. }
  494.  
  495. void LoadDirectoryHoleList(void)
  496. {
  497.     FILE *holeFile;
  498.     HOLE *hole;
  499.     HOLE *prevHole;
  500.     time_t t;
  501.     int holes;
  502.     unsigned oldest;
  503.     unsigned start, finish;
  504.  
  505.     /* prune back the list */
  506.     time(&t);
  507.     oldest = (unsigned)t - (60 * 60 * 24 * maxDays);
  508.  
  509.     if ((holeFile = fopen("pfhdir.hol", "r")) != NULL)
  510.     {
  511.         fscanf(holeFile, "%d %*s %*s %*s", &of[MAXFILES].hdrSeen);
  512.         fscanf(holeFile, "%d %*s %*s %*s", &of[MAXFILES].fileSize);
  513.         fscanf(holeFile, "%d %*s", &holes);
  514.  
  515.         prevHole = NULL;
  516.  
  517.         of[MAXFILES].holes = 0;
  518.  
  519.         while (holes-- > 0)
  520.         {
  521.             fscanf(holeFile, "%u, %u", &start, &finish);
  522.  
  523.             if (finish > oldest)
  524.             {
  525.                 hole           = (HOLE *)XtMalloc(sizeof(HOLE));
  526.                 hole->nextHole = NULL;
  527.  
  528.                 hole->start    = (start < oldest) ? oldest : start;
  529.                 hole->finish   = finish;
  530.  
  531.                 if (prevHole == NULL)
  532.                     of[MAXFILES].firstHole = hole;
  533.                 else
  534.                     prevHole->nextHole = hole;
  535.  
  536.                 prevHole = hole;
  537.  
  538.                 of[MAXFILES].holes++;
  539.             }
  540.         }
  541.     
  542.         fclose(holeFile);
  543.     }
  544.     else
  545.     {
  546.         /* create an empty hole list */
  547.         of[MAXFILES].firstHole           = (HOLE *)XtMalloc(sizeof(HOLE));
  548.         of[MAXFILES].firstHole->start    = oldest;
  549.         of[MAXFILES].firstHole->finish   = 0xFFFFFFFF;
  550.         of[MAXFILES].firstHole->nextHole = NULL;
  551.         of[MAXFILES].holes               = 1;
  552.  
  553.         /* use file size as file number - start at 1 */
  554.         of[MAXFILES].fileSize            = 1;
  555.     }
  556. }
  557.  
  558. void SaveHoleList(int f, char *fileName)
  559. {
  560.     char buffer[40];
  561.     FILE *holeFile;
  562.     HOLE *hole;
  563.  
  564.     if ((holeFile = fopen(fileName, "w")) == NULL)
  565.     {
  566.         sprintf(buffer, "Cannot open file %s", fileName);
  567.         MessageBox(buffer);
  568.         return;
  569.     }
  570.     
  571.     fprintf(holeFile, "%d pfh header received\n", of[f].hdrSeen);
  572.     fprintf(holeFile, "%d pfh file length\n", of[f].fileSize);
  573.     fprintf(holeFile, "%d holes\n", of[f].holes);
  574.  
  575.     hole = of[f].firstHole;
  576.  
  577.     while (hole != NULL)
  578.     {
  579.         fprintf(holeFile, "%u, %u\n", hole->start, hole->finish);
  580.         hole = hole->nextHole;
  581.     }
  582.  
  583.     fclose(holeFile);
  584. }
  585.  
  586. int UpdateHoleList(int f, unsigned start, unsigned finish)
  587. {
  588.     HOLE *h, *p, *n;
  589.  
  590.     for (p = NULL, h = of[f].firstHole; h != NULL; p = h, h = h->nextHole)
  591.     {
  592.         /* see if this is a candidate */
  593.         if (start <= h->finish && finish >= h->start)
  594.         {
  595.             if (start == h->start && finish == h->finish)
  596.             {
  597.                 /* exact match - will remove all of it */
  598.                 if (p == NULL)
  599.                     of[f].firstHole = h->nextHole;
  600.                 else
  601.                     p->nextHole = h->nextHole;
  602.  
  603.                 of[f].holes--;
  604.                 XtFree((char *)h);
  605.                 return(FILL_UNIQUE);
  606.             }
  607.  
  608.             if (start <= h->start && finish >= h->finish)
  609.             {
  610.                 /* larger - will remove all of it */
  611.                 if (p == NULL)
  612.                     of[f].firstHole = h->nextHole;
  613.                 else
  614.                     p->nextHole = h->nextHole;
  615.  
  616.                 of[f].holes--;
  617.                 XtFree((char *)h);
  618.                 return(FILL_OVERLAP);
  619.             }
  620.  
  621.             if (start == h->start && finish < h->finish)
  622.             {
  623.                 /* remove the front part */
  624.                 h->start = finish + 1;
  625.                 return(FILL_UNIQUE);
  626.             }
  627.  
  628.             if (start < h->start && finish < h->finish)
  629.             {
  630.                 /* remove the front part */
  631.                 h->start = finish + 1;
  632.                 return(FILL_OVERLAP);
  633.             }
  634.  
  635.             if (start > h->start && finish == h->finish)
  636.             {
  637.                 /* will remove the end */
  638.                 h->finish = start - 1;
  639.                 return(FILL_UNIQUE);
  640.             }
  641.  
  642.             if (start > h->start && finish > h->finish)
  643.             {
  644.                 /* will remove the end */
  645.                 h->finish = start - 1;
  646.                 return(FILL_OVERLAP);
  647.             }
  648.  
  649.             if (start > h->start && finish < h->finish)
  650.             {
  651.                 /* remove the middle */
  652.                 n = (HOLE *)XtMalloc(sizeof(HOLE));
  653.                 n->start    = finish + 1;
  654.                 n->finish   = h->finish;
  655.                 n->nextHole = h->nextHole;
  656.  
  657.                 /* change the current hole for the first part */
  658.                 h->finish   = start - 1;
  659.                 h->nextHole = n;
  660.  
  661.                 /* one more hole */
  662.                 of[f].holes++;
  663.                 return(FILL_UNIQUE);
  664.             }
  665.         }
  666.     }
  667.  
  668.     return(FILL_NONE);
  669. }
  670.  
  671. /*
  672.  * Message file maintenance
  673.  */
  674. void LoadFile(int fileId, int f)
  675. {
  676.     char buffer[80];
  677.     char holeName[40];
  678.     char fileName[40];
  679.  
  680.     /* save this file id */
  681.     of[f].fileId = fileId;
  682.  
  683.     /* load the hole file and open the data file */
  684.     sprintf(fileName, "%x.act", of[f].fileId);
  685.     sprintf(holeName, "%x.hol", of[f].fileId);
  686.  
  687.     if (LoadHoleList(f, holeName, fileName))
  688.     {
  689.         if ((of[f].file = fopen(fileName, "r+")) == NULL)
  690.         {
  691.             sprintf(buffer, "Cannot open file %s", fileName);
  692.             MessageBox(buffer);
  693.         }
  694.     }
  695.     else
  696.     {
  697.         if ((of[f].file = fopen(fileName, "w+")) == NULL)
  698.         {
  699.             sprintf(buffer, "Cannot open file %s", fileName);
  700.             MessageBox(buffer);
  701.         }
  702.     }
  703. }
  704.  
  705. void SaveFile(int f)
  706. {
  707.     HOLE *hole;
  708.     HOLE *next;
  709.     char fileName[40];
  710.  
  711.     if (of[f].file != NULL)
  712.     {
  713.         sprintf(writebuf, "saving file %x\n", of[f].fileId);
  714.         writetext(writebuf);
  715.  
  716.         /* close the data file */
  717.         fclose(of[f].file);
  718.  
  719.         /* write out the hole list */
  720.         sprintf(fileName, "%x.hol", of[f].fileId);
  721.         SaveHoleList(f, fileName);
  722.  
  723.         /* clean up the file table */
  724.         of[f].fileId   = 0;
  725.         of[f].file     = NULL;
  726.         of[f].hdrSeen  = 0;
  727.         of[f].fileSize = 0;
  728.         of[f].holes    = 0;
  729.  
  730.         /* free the hole list */
  731.         hole = of[f].firstHole;
  732.  
  733.         while (hole != NULL)
  734.         {
  735.             next = hole->nextHole;
  736.             XtFree((char *)hole);
  737.             hole = next;
  738.         }
  739.  
  740.         of[f].firstHole = NULL;
  741.     }
  742. }
  743.  
  744. void CheckDownloaded(int f)
  745. {
  746.     int headerSize;
  747.     HEADER *hdr;
  748.     HOLE *h;
  749.     unsigned char *buf;
  750.     char oldName[80];
  751.     char newName[80];
  752.     char holeName[80];
  753.  
  754.     /* see if we have the header */
  755.     if (of[f].hdrSeen == 0)
  756.     {
  757.         h = of[f].firstHole;
  758.  
  759.         if (h->start != 0)
  760.         {
  761.             /* read the header into a buffer */
  762.             if ((buf = XtMalloc(h->start)) != NULL)
  763.             {
  764.                 fseek(of[f].file, 0L, SEEK_SET);
  765.                 fread(buf, 1, h->start, of[f].file);
  766.  
  767.                 if ((hdr = ExtractHeader(buf, h->start, &headerSize)) != NULL)
  768.                 {
  769.                     of[f].hdrSeen  = 1;
  770.                     of[f].fileSize = hdr->fileSize;
  771.                     UpdateHoleList(f, (unsigned)of[f].fileSize, (unsigned)0xFFFFFFFF);
  772.                     XtFree((char *)hdr);
  773.                 }
  774.  
  775.                 XtFree(buf);
  776.             }
  777.         }
  778.     }
  779.  
  780.     /* see if we now have the complete file */
  781.     if (of[f].holes == 0 && of[f].hdrSeen == 1)
  782.     {
  783.         unsigned long fileId;
  784.  
  785.         /* close the current file */
  786.         fileId = of[f].fileId;
  787.         SaveFile(f);
  788.  
  789.         /* rename the file */
  790.         sprintf(oldName, "%lx.act", fileId);
  791.         sprintf(newName, "%lx.dl", fileId);
  792.         rename(oldName, newName);
  793.  
  794.         /* remove the hole file */
  795.         sprintf(holeName, "%lx.hol", fileId);
  796.         unlink(holeName);
  797.  
  798.         /* let the user know */
  799.         sprintf(writebuf, "%lx downloaded\n", fileId);
  800.         writetext(writebuf);
  801.     }
  802. }
  803.  
  804. void BroadcastFile(unsigned char *buffer, int length)
  805. {
  806.     static unsigned HeardId = 0;
  807.     static unsigned DupId   = 0;
  808.     FILEHEADER *fh;
  809.     unsigned char *data;
  810.     unsigned dataOffset;
  811.     unsigned dataLength;
  812.     char fileName[80];
  813.     FILE *fp;
  814.     int i;
  815.  
  816.     /* crc validation */
  817.     if (!CheckCRC(buffer, length))
  818.     {
  819.         crcErrors++;
  820.         UpdateStatus();
  821.         return;
  822.     }
  823.  
  824.     /* point to the header */
  825.     fh = (FILEHEADER *)buffer;
  826.  
  827.     /* point to the data */
  828.     data       = buffer + sizeof(FILEHEADER);
  829.     dataOffset = fh->wOffset + (fh->nOffsetHigh << 16);
  830.     dataLength = length - sizeof(FILEHEADER) - CRCLENGTH;
  831.     
  832.     /* inform the user */
  833.     if (fh->fileId != HeardId)
  834.     {
  835.         sprintf(writebuf, "heard message %x\n", fh->fileId);
  836.         writetext(writebuf);
  837.         HeardId = fh->fileId;
  838.         DupId   = -1;
  839.     }
  840.  
  841.     /* see if the file already downloaded */
  842.     sprintf(fileName, "%x.dl", fh->fileId);
  843.  
  844.     if ((fp = fopen(fileName, "r")) != NULL)
  845.     {
  846.         fclose(fp);
  847.  
  848.         if (fh->fileId != DupId)
  849.         {
  850.             sprintf(writebuf, "%x is already downloaded\n", fh->fileId);
  851.             writetext(writebuf);
  852.             DupId = fh->fileId;
  853.         }
  854.  
  855.         return;
  856.     }
  857.  
  858.     /* see if the file is in the current list of files */
  859.     for (i = 0; i < MAXFILES; i++)
  860.         if (of[i].fileId == fh->fileId)
  861.             break;
  862.  
  863.     /* if it is not there then we must load it */
  864.     if (i == MAXFILES)
  865.     {
  866.         /* save current file if used */
  867.         SaveFile(nextof);
  868.  
  869.         /* now use this slot */
  870.         LoadFile(fh->fileId, nextof);
  871.         
  872.         /* setup i for this entry */
  873.         i = nextof;
  874.  
  875.         /* make sure we round robin the open files */
  876.         nextof = (nextof + 1) % MAXFILES;
  877.     }
  878.  
  879.     if (UpdateHoleList(i, (unsigned)dataOffset, (unsigned)(dataOffset + dataLength - 1)) != FILL_NONE)
  880.     {
  881.         /* write the data */
  882.         fseek(of[i].file, dataOffset, SEEK_SET);
  883.         fwrite(data, 1, dataLength, of[i].file);
  884.  
  885.         /* see if it has all been downloaded */
  886.         CheckDownloaded(i);
  887.     }
  888. }
  889.  
  890. /*
  891.  *    Directory Maintenance
  892.  */
  893. void WriteDirectory(unsigned char *data, int dataLength)
  894. {
  895.     char buffer[80];
  896.     char fileName[40];
  897.     struct stat statbuf;
  898.     FILE *fp;
  899.  
  900.     sprintf(fileName, "pb__%04d.pfh", of[MAXFILES].fileSize);
  901.  
  902.     /* write the data to the end of the current file */
  903.     if ((fp = fopen(fileName, "a")) == NULL)
  904.     {
  905.         sprintf(buffer, "Cannot open file %s", fileName);
  906.         MessageBox(buffer);
  907.         return;
  908.     }
  909.  
  910.     fwrite(data, 1, dataLength, fp);
  911.     fclose(fp);
  912.  
  913.     stat(fileName, &statbuf);
  914.  
  915.     /* limit file size to 20000 bytes */
  916.     if (statbuf.st_size > 20000) of[MAXFILES].fileSize++;
  917. }
  918.  
  919. void BroadcastDirectory(unsigned char *buffer, int length)
  920. {
  921.     static unsigned int  fragmentId     = 0;
  922.     static unsigned int  fragmentOffset = 0;
  923.     static unsigned char fragmentBuffer[1024];
  924.     DIRHEADER *dh;
  925.     int headerSize;
  926.     HEADER *hdr;
  927.     unsigned char *data;
  928.     int dataLength;
  929.     int i;
  930.  
  931.     /* crc validation */
  932.     if (!CheckCRC(buffer, length))
  933.     {
  934.         crcErrors++;
  935.         UpdateStatus();
  936.         return;
  937.     }
  938.  
  939.     /* point to the header */
  940.     dh = (DIRHEADER *)buffer;
  941.  
  942.     /* check for fragmented directory header */
  943.     if (dh->offset != 0)
  944.     {
  945.         /* see if this is the next fragment */
  946.         if (fragmentId == dh->fileId && dh->offset == fragmentOffset)
  947.         {
  948.             /* append this fragment */
  949.             data       = buffer + sizeof(DIRHEADER);
  950.             dataLength = length - sizeof(DIRHEADER) - CRCLENGTH;
  951.  
  952.             for (i = 0; i < dataLength; i++)
  953.                 fragmentBuffer[fragmentOffset + i] = data[i];
  954.  
  955.             fragmentOffset += dataLength;
  956.  
  957.             if ((dh->flags & LASTBYTEFLAG) != LASTBYTEFLAG)
  958.             {
  959.                 data       = fragmentBuffer;
  960.                 dataLength = fragmentOffset;
  961.             }
  962.             else
  963.             {
  964.                 return;
  965.             }
  966.         }
  967.         else
  968.         {
  969.             fragmentId     = 0;
  970.             fragmentOffset = 0;
  971.             return;
  972.         }
  973.     }
  974.     else if ((dh->flags & LASTBYTEFLAG) != LASTBYTEFLAG)
  975.     {
  976.         /* copy the fragment */
  977.         data       = buffer + sizeof(DIRHEADER);
  978.         dataLength = length - sizeof(DIRHEADER) - CRCLENGTH;
  979.  
  980.         for (i = 0; i < dataLength; i++)
  981.             fragmentBuffer[i] = data[i];
  982.  
  983.         /* start a new fragment */
  984.         fragmentId     = dh->fileId;
  985.         fragmentOffset = dataLength;
  986.  
  987.         return;
  988.     }
  989.     else
  990.     {
  991.         /* its all there -  point to the data */
  992.         data       = buffer + sizeof(DIRHEADER);
  993.         dataLength = length - sizeof(DIRHEADER) - CRCLENGTH;
  994.     }
  995.  
  996.     if ((dh->flags & LASTBYTEFLAG) == LASTBYTEFLAG)
  997.     {
  998.         /* reset fragmentation */
  999.         fragmentId     = 0;
  1000.         fragmentOffset = 0;
  1001.  
  1002.         /* try to extract the header */
  1003.         if ((hdr = ExtractHeader(data, dataLength, &headerSize)) != NULL)
  1004.         {
  1005.             /* inform the user */
  1006.             if (strlen(hdr->title) == 0)
  1007.                 sprintf(writebuf, "dir: %lx: from:%s to:%s title:%s\n",
  1008.                     hdr->fileId,
  1009.                     hdr->source,
  1010.                     hdr->destination,
  1011.                     hdr->fileName);
  1012.             else
  1013.                 sprintf(writebuf, "dir: %lx: from:%s to:%s title:%s\n",
  1014.                     hdr->fileId,
  1015.                     hdr->source,
  1016.                     hdr->destination,
  1017.                     hdr->title);
  1018.  
  1019.             writetext(writebuf);
  1020.  
  1021.             /* see if the hole list is loaded */
  1022.             if (of[MAXFILES].firstHole == NULL)
  1023.                 LoadDirectoryHoleList();
  1024.  
  1025.             /* update the directory  if needed */
  1026.             if (UpdateHoleList(MAXFILES, dh->tOld, dh->tNew) == FILL_UNIQUE)
  1027.                 WriteDirectory(data, dataLength);
  1028.  
  1029.             XtFree((char *)hdr);
  1030.         }
  1031.         else
  1032.         {
  1033.             sprintf(writebuf, "** Bad directory header for %x\n", dh->fileId);
  1034.             writetext(writebuf);
  1035.         }
  1036.     }
  1037. }
  1038.  
  1039. /*
  1040.  *    decode a received frame.
  1041.  */
  1042. void ProcessFrame(void)
  1043. {
  1044.     int n, i;
  1045.     int via;
  1046.     unsigned char protocol;
  1047.     char toCall[10];
  1048.     char fromCall[10];
  1049.     char viaCall[10];
  1050.     char *s;
  1051.  
  1052.     /* check that frame is a kiss data frame */
  1053.     /* ignore control frames - should not happen */
  1054.     n = 0;
  1055.  
  1056.     if ((buf[n] & 0x0F) == 0)
  1057.     {
  1058.         n++;
  1059.  
  1060.         bytes += bufSize - 1;
  1061.  
  1062.         if (fpkiss != NULL)
  1063.         {
  1064.             fputc(0300, fpkiss);        /* FEND */
  1065.             fputc(0x00, fpkiss);        /* KISS Data */
  1066.  
  1067.             for (i = n; i < bufSize; i++)
  1068.             {
  1069.                 switch (buf[i])
  1070.                 {
  1071.                     case 0300:    /* FEND */
  1072.                         fputc(0333, fpkiss);    /* FESC */
  1073.                         fputc(0334, fpkiss);    /* FESC_END */
  1074.                         break;
  1075.                     case 0333:    /* FESC */
  1076.                         fputc(0333, fpkiss);    /* FESC */
  1077.                         fputc(0335, fpkiss);    /* FESC_ESC */
  1078.                         break;
  1079.                     default:
  1080.                         fputc(buf[i], fpkiss);
  1081.                         break;
  1082.                 }
  1083.             }
  1084.  
  1085.             fputc(0300, fpkiss);        /* FEND */
  1086.         }
  1087.  
  1088.         /* decode the to/from address */
  1089.         /* dont expect via address, but saves last if any */
  1090.         via = ConvertCall(buf + n, toCall);
  1091.         n += 7;
  1092.  
  1093.         via = ConvertCall(buf + n, fromCall);
  1094.         n += 7;
  1095.  
  1096.         while (via)
  1097.         {
  1098.             via = ConvertCall(buf + n, viaCall);
  1099.             n += 7;
  1100.         }
  1101.  
  1102.         /* check for a UI frame */
  1103.         if ((buf[n] & 0xEF) == 0003)
  1104.         {
  1105.             n++;
  1106.             protocol = buf[n++];
  1107.  
  1108.             /* see if the frame is a broadcast frame */    
  1109.             if (strcmp(toCall, "QST-1") == 0)
  1110.             {
  1111.                 switch (protocol)
  1112.                 {
  1113.                 case PID_FILE:
  1114.                     fileBytes += bufSize - n;
  1115.                     BroadcastFile(buf + n,  bufSize - n);
  1116.                     break;
  1117.                 case PID_DIRECTORY:
  1118.                     dirBytes += bufSize - n;
  1119.                     BroadcastDirectory(buf + n, bufSize - n);
  1120.                     break;
  1121.                 default:
  1122.                     break;
  1123.                 }
  1124.             }
  1125.             else if (strcmp(toCall, "PBLIST") == 0)
  1126.             {
  1127.                 buf[bufSize] = '\0';
  1128.                 sprintf(writebuf, "%s\n", buf + n);
  1129.                 writetext(writebuf);
  1130.  
  1131.                 if (strstr(buf + n, myCall) == NULL)
  1132.                 {
  1133.                     switch (request_state)
  1134.                     {
  1135.                         case REQUEST_DIR:
  1136.                             FillDirectory();
  1137.                             break;
  1138.                         case REQUEST_FILE:
  1139.                             FillFile();
  1140.                             break;
  1141.                     }
  1142.                 }
  1143.                 else
  1144.                 {
  1145.                     request_state = REQUEST_NONE;
  1146.                 }
  1147.             }
  1148.             else if (strcmp(toCall, "TLM") == 0)
  1149.             {
  1150.                 tlmBytes += bufSize - n;
  1151.  
  1152.                 if (!CheckCRC(buf + n, bufSize - n))
  1153.                 {
  1154.                     crcErrors++;
  1155.                     UpdateStatus();
  1156.                     return;
  1157.                 }
  1158.  
  1159.                 if (fptlm != NULL)
  1160.                 {
  1161.                     fputc((bufSize - n) % 256, fptlm);
  1162.                     fputc((bufSize - n) / 256, fptlm);
  1163.                     fwrite(buf + n, 1, bufSize - n, fptlm);
  1164.                 }
  1165.             }
  1166.             else
  1167.             {
  1168.                 buf[bufSize] = '\0';
  1169.                 sprintf(writebuf, "%s\n", buf + n);
  1170.                 writetext(writebuf);
  1171.  
  1172.                 if (request_state == REQUEST_FILE &&
  1173.                     protocol      == PID_FILE     &&
  1174.                     strcmp(toCall, myCall) == 0   &&
  1175.                     strncmp(buf + n, "NO -2 ", 6) == 0)
  1176.                 {
  1177.                     request_state = REQUEST_NONE;
  1178.                     sprintf(writebuf, "** File %s not present, request cancelled\n", id);
  1179.                     writetext(writebuf);
  1180.                 }
  1181.             }
  1182.         }
  1183.     }
  1184.  
  1185.     UpdateStatus();
  1186. }
  1187.  
  1188. /*
  1189.  *    callback function when a frame is received.
  1190.  */
  1191. void GetFrame(XtPointer closure, int *s, XtInputId *Id)
  1192. {
  1193.     if ((bufSize = recv(s_raw, buf, MAXBUFFER, 0)) == -1)
  1194.     {
  1195.         perror("recv");
  1196.         return;
  1197.     }
  1198.  
  1199.     time(&end_time);
  1200.     
  1201.     if (start_time == 0) start_time = end_time;
  1202.  
  1203.     ProcessFrame();
  1204. }
  1205.  
  1206. /*
  1207.  * Timeout has occured, flush the directory hole list.
  1208.  */
  1209. void TimeoutCb(XtPointer closure, XtIntervalId *id)
  1210. {
  1211. #ifdef FLUSH_FILES
  1212.     char fileName[40];
  1213.     int i;
  1214.  
  1215.     for (i = 0; i < MAXFILES; i++)
  1216.     {
  1217.         if (of[i].file != NULL)
  1218.         {
  1219.             /* write out the hole list */
  1220.             sprintf(fileName, "%x.hol", of[i].fileId);
  1221.             SaveHoleList(i, fileName);
  1222.         }
  1223.     }
  1224. #endif
  1225.  
  1226.     /* save the directory hole list */
  1227.     if (of[MAXFILES].firstHole != NULL)
  1228.         SaveHoleList(MAXFILES, "pfhdir.hol");
  1229.  
  1230.     XtAppAddTimeOut(app_context, TIMEOUT * 1000, TimeoutCb, NULL);
  1231. }
  1232.  
  1233. /*
  1234.  *    callback function when a another app calls us
  1235.  */
  1236. void FillRequest(XtPointer closure, int *s, XtInputId *Id)
  1237. {
  1238.     struct request request;
  1239.  
  1240.     if (recv(s_request, (char *)&request, sizeof(struct request), 0) == sizeof(struct request))
  1241.     {
  1242.         switch (request.type)
  1243.         {
  1244.             case REQ_TYPE_CANCEL:
  1245.                 CancelFill();
  1246.                 break;
  1247.             case REQ_TYPE_DIR:
  1248.                 FillDirectory();
  1249.                 break;
  1250.             case REQ_TYPE_FILE:
  1251.                 sprintf(id, "%lx", request.fileId);
  1252.                 XtVaSetValues(filetext, XtNstring, id, NULL);
  1253.                 XawTextSetInsertionPoint(filetext, strlen(id));
  1254.                 FillFile();
  1255.                 break;
  1256.         }
  1257.     }
  1258.     else
  1259.     {
  1260.         perror("recv - FillRequest");
  1261.     }
  1262. }
  1263.  
  1264. /*
  1265.  *    the user wants to exit this program
  1266.  */
  1267. void QuitCb(Widget w, XtPointer client_data, XtPointer call_data)
  1268. {
  1269.     FILE *fp;
  1270.     struct tm *tm;
  1271.     int ave_rate = 0, i;
  1272.  
  1273.     if (fptlm != NULL)  fclose(fptlm);
  1274.     if (fpkiss != NULL) fclose(fpkiss);
  1275.  
  1276.     /* save any open files */
  1277.     for (i = 0; i < MAXFILES; i++)
  1278.         SaveFile(i);
  1279.  
  1280.     /* save the directory hole list */
  1281.     if (of[MAXFILES].firstHole != NULL)
  1282.         SaveHoleList(MAXFILES, "pfhdir.hol");
  1283.  
  1284.     /* close the sockets */
  1285.     close(s_raw);
  1286.     close(s_file);
  1287.     close(s_directory);
  1288.  
  1289.     /* write the statistics out */
  1290.     if (start_time != 0)
  1291.     {
  1292.         if ((fp = fopen("pb.log", "a")) != NULL)
  1293.         {
  1294.             if (end_time - start_time > 0)
  1295.                 ave_rate = bytes / (end_time - start_time);
  1296.  
  1297.             tm = gmtime(&start_time);
  1298.             fprintf(fp, "%02d/%02d/%02d %02d:%02d:%02d - ",
  1299.                 tm->tm_mday, tm->tm_mon + 1, tm->tm_year,
  1300.                 tm->tm_hour, tm->tm_min, tm->tm_sec);
  1301.  
  1302.             tm = gmtime(&end_time);
  1303.             fprintf(fp, "%02d:%02d:%02d - total %d files %d dir %d tlm %d ave %d crc %d\n",
  1304.                 tm->tm_hour, tm->tm_min, tm->tm_sec,
  1305.                 bytes, fileBytes, dirBytes, tlmBytes, ave_rate, crcErrors);
  1306.     
  1307.             fclose(fp);
  1308.         }
  1309.     }
  1310.  
  1311.     XtDestroyApplicationContext(app_context);
  1312.  
  1313.     exit(0);
  1314. }
  1315.  
  1316. void KissCb(Widget w, XtPointer client_data, XtPointer call_data)
  1317. {
  1318.     char fileName[20];
  1319.     Arg args[1];
  1320.     time_t t;
  1321.  
  1322.     if (fpkiss == NULL)
  1323.     {
  1324.         time(&t);
  1325.         
  1326.         sprintf(fileName, "%x.kss", (int)t);
  1327.         
  1328.         if ((fpkiss = fopen(fileName, "w")) == NULL)
  1329.             return;
  1330.             
  1331.         XtSetArg(args[0], XtNlabel, "KISS Log On");
  1332.     }
  1333.     else
  1334.     {
  1335.         fclose(fpkiss);
  1336.         fpkiss = NULL;
  1337.  
  1338.         XtSetArg(args[0], XtNlabel, "KISS Log Off");
  1339.     }
  1340.  
  1341.     XtSetValues(kissbutton, args, ONE);
  1342. }
  1343.  
  1344. void TLMCb(Widget w, XtPointer client_data, XtPointer call_data)
  1345. {
  1346.     char fileName[20];
  1347.     Arg args[1];
  1348.     time_t t;
  1349.  
  1350.     if (fptlm == NULL)
  1351.     {
  1352.         time(&t);
  1353.  
  1354.         sprintf(fileName, "%x.tlm", (int)t);
  1355.  
  1356.         if ((fptlm = fopen(fileName, "w")) == NULL)
  1357.             return;
  1358.             
  1359.         XtSetArg(args[0], XtNlabel, "TLM Log On");
  1360.     }
  1361.     else
  1362.     {
  1363.         fclose(fptlm);
  1364.         fptlm = NULL;
  1365.  
  1366.         XtSetArg(args[0], XtNlabel, "TLM Log Off");
  1367.     }
  1368.  
  1369.     XtSetValues(tlmbutton, args, ONE);
  1370. }
  1371.  
  1372. /*
  1373.  *    Construct a fill request for the directory.
  1374.  */
  1375. void FillDirectory(void)
  1376. {
  1377.     DIRREQUESTHEADER *request;
  1378.     DIRHOLEPAIR *hole;
  1379.     HOLE *h;
  1380.     unsigned char *buffer;
  1381.     int i;
  1382.  
  1383.     /* see if the hole list is loaded */
  1384.     if (of[MAXFILES].firstHole == NULL)
  1385.         LoadDirectoryHoleList();
  1386.  
  1387.     /* construct a hole list request */
  1388.     buffer = (unsigned char *)XtMalloc(256);
  1389.     request = (DIRREQUESTHEADER *)buffer;
  1390.  
  1391.     request->flags     = 0x00 | VERSION | 0x10;
  1392.     request->blockSize = 244;
  1393.  
  1394.     hole = (DIRHOLEPAIR *)&buffer[sizeof(DIRREQUESTHEADER)];
  1395.     h = of[MAXFILES].firstHole;
  1396.     for (i = 0; i < 10 && i < of[MAXFILES].holes; i++)
  1397.     {
  1398.         hole->startTime = h->start;
  1399.         hole->endTime   = h->finish;
  1400.         h = h->nextHole;
  1401.         hole++;
  1402.     }
  1403.  
  1404.     if (sendto(s_directory, buffer,
  1405.            sizeof(DIRREQUESTHEADER) + (i * sizeof(DIRHOLEPAIR)),
  1406.            0, (struct sockaddr *)&dest, sizeof(dest)) == -1)
  1407.         perror("send");
  1408.  
  1409.     sprintf(writebuf, "Fill Directory: fill %d holes.\n", i);
  1410.     writetext(writebuf);
  1411.  
  1412.     XtFree(buffer);
  1413.  
  1414.     request_state = REQUEST_DIR;
  1415. }
  1416.  
  1417. void FillDirectoryCb(Widget w, XtPointer client_data, XtPointer call_data)
  1418. {
  1419.     FillDirectory();
  1420. }
  1421.  
  1422. /*
  1423.  *    construct a fill request for a file
  1424.  */
  1425. void FillFile(void)
  1426. {
  1427.     unsigned int fileId;
  1428.     char fileName[80];
  1429.     unsigned char *buffer;
  1430.     REQUESTHEADER *request;
  1431.     HOLEPAIR *hole;
  1432.     HOLE *h;
  1433.     FILE *fp;
  1434.     int f, i;
  1435.  
  1436.     if (strlen(id) == 0) return;
  1437.     sscanf(id, "%x", &fileId);
  1438.     if (fileId == 0) return;
  1439.  
  1440.     /* see if the file already downloaded */
  1441.     sprintf(fileName, "%x.dl", fileId);
  1442.     if ((fp = fopen(fileName, "r")) != NULL)
  1443.     {
  1444.         fclose(fp);
  1445.         sprintf(writebuf, "%x is already downloaded\n", fileId);
  1446.         writetext(writebuf);
  1447.         return;
  1448.     }
  1449.  
  1450.     /* see if the file is in the current list of files */
  1451.     for (f = 0; f < MAXFILES; f++)
  1452.         if (of[f].fileId == fileId)
  1453.             break;
  1454.  
  1455.     if (f == MAXFILES)
  1456.     {
  1457.         /* not there - must save if this is in use */
  1458.         SaveFile(nextof);
  1459.  
  1460.         /* now use this slot */
  1461.         LoadFile(fileId, nextof);
  1462.  
  1463.         /* make sure we round robin the files */
  1464.         f = nextof;
  1465.         nextof = (nextof + 1) % MAXFILES;
  1466.     }
  1467.  
  1468.     buffer  = (unsigned char *)XtMalloc(256);
  1469.     request = (REQUESTHEADER *)buffer;
  1470.  
  1471.     if (of[f].holes == 1 && of[f].firstHole->start  == 0 &&
  1472.                 of[f].firstHole->finish == 0xFFFFFFFF)
  1473.     {
  1474.         request->flags     = 0x00 | VERSION | 0x10;
  1475.         request->fileId    = fileId;
  1476.         request->blockSize = 244;
  1477.  
  1478.         if (sendto(s_file, buffer, sizeof(REQUESTHEADER), 0,
  1479.             (struct sockaddr *)&dest, sizeof(dest)) == -1)
  1480.             perror("send");
  1481.  
  1482.         sprintf(writebuf, "Fill File: %x send file.\n", fileId);
  1483.         writetext(writebuf);
  1484.     }
  1485.     else
  1486.     {
  1487.         request->flags     = 0x02 | VERSION | 0x10;
  1488.         request->fileId    = fileId;
  1489.         request->blockSize = 244;
  1490.  
  1491.         hole = (HOLEPAIR *)&buffer[sizeof(REQUESTHEADER)];
  1492.         h = of[f].firstHole;
  1493.  
  1494.         for (i = 0; i < 10 && i < of[f].holes; i++)
  1495.         {
  1496.             hole->offset     = h->start;
  1497.             hole->offset_msb = h->start >> 16;
  1498.             hole->length     = 1 + (h->finish - h->start);
  1499.             h = h->nextHole;
  1500.             hole++;
  1501.         }
  1502.  
  1503.         if (sendto(s_file, buffer,
  1504.                 sizeof(REQUESTHEADER) + (i * sizeof(HOLEPAIR)), 0,
  1505.                 (struct sockaddr *)&dest, sizeof(dest)) == -1)
  1506.             perror("send");
  1507.  
  1508.         sprintf(writebuf, "Fill File: %x fill %d holes.\n", fileId, i);
  1509.         writetext(writebuf);
  1510.     }
  1511.  
  1512.     XtFree(buffer);
  1513.  
  1514.     request_state = REQUEST_FILE;
  1515. }
  1516.  
  1517. void FillFileCb(Widget w, XtPointer client_data, XtPointer call_data)
  1518. {
  1519.     FillFile();
  1520. }
  1521.  
  1522. void CancelFill(void)
  1523. {
  1524.     switch (request_state)
  1525.     {
  1526.         case REQUEST_DIR:
  1527.             writetext("Cancel Fill: directory\n");
  1528.             break;
  1529.         case REQUEST_FILE:
  1530.             sprintf(writebuf, "Cancel Fill: file %s\n", id);
  1531.             writetext(writebuf);
  1532.             break;
  1533.         default:
  1534.             break;
  1535.     }
  1536.  
  1537.     request_state = REQUEST_NONE;
  1538. }
  1539.  
  1540. void CancelFillCb(Widget w, XtPointer client_data, XtPointer call_data)
  1541. {
  1542.     CancelFill();
  1543. }
  1544.  
  1545. int main(int argc, char **argv)
  1546. {
  1547.     static XtCallbackRec callback[2];
  1548.     int n;
  1549.     char *s, title[80];
  1550.  
  1551.     if ((s = getenv("SATELLITE")) == NULL)
  1552.     {
  1553.         printf("SATELLITE environment variable not set.\n");
  1554.         return(1);
  1555.     }
  1556.  
  1557.     strcpy(satelliteId, s);
  1558.  
  1559.     if ((s = getenv("MYCALL")) == NULL)
  1560.     {
  1561.         printf("MYCALL environment variable not set.\n");
  1562.         return(1);
  1563.     }
  1564.  
  1565.     strcpy(myCall, s);
  1566.  
  1567.     if ((s = getenv("MAXDAYS")) != NULL)
  1568.     {
  1569.         maxDays = atoi(s);
  1570.         if (maxDays <= 0) maxDays = 5;
  1571.     }
  1572.  
  1573.     sprintf(title, "xpb:%s %s", satelliteId, VERSION_STRING);
  1574.  
  1575.     strcat(satelliteId, "-11");
  1576.     MakeAddress(myCall, &src);
  1577.     MakeAddress(satelliteId, &dest);
  1578.  
  1579.     toplevel = XtAppInitialize(&app_context, "Xpb", NULL, 0, &argc, argv,
  1580.                 NULL, shell_args, XtNumber(shell_args));
  1581.     XtVaSetValues(toplevel, XtNtitle, title, NULL);
  1582.  
  1583.     dpy  = XtDisplay(toplevel);
  1584.  
  1585.     XtGetApplicationResources(toplevel, &resources,
  1586.                 resource_list, XtNumber(resource_list),
  1587.                 NULL, ZERO);
  1588.  
  1589.     compwindow = XtCreateManagedWidget("appForm", formWidgetClass,
  1590.                 toplevel, form_args, XtNumber(form_args));
  1591.  
  1592.     callback[0].callback = QuitCb;
  1593.     callback[0].closure  = toplevel;
  1594.     button_args[0].value = (XtArgVal)callback;
  1595.     button_args[1].value = (XtArgVal)"Quit";
  1596.     button_args[3].value = (XtArgVal)resources.button_font;
  1597.     quitbutton = XtCreateManagedWidget("quitButton", commandWidgetClass,
  1598.                 compwindow, button_args, XtNumber(button_args));
  1599.  
  1600.     callback[0].callback = KissCb;
  1601.     callback[0].closure  = toplevel;
  1602.     button_args[0].value = (XtArgVal)callback;
  1603.     button_args[1].value = (XtArgVal)"KISS Log Off";
  1604.     button_args[2].value = (XtArgVal)quitbutton;
  1605.     kissbutton = XtCreateManagedWidget("kissButton", commandWidgetClass,
  1606.                 compwindow, button_args, XtNumber(button_args));
  1607.  
  1608.     callback[0].callback = TLMCb;
  1609.     callback[0].closure  = toplevel;
  1610.     button_args[0].value = (XtArgVal)callback;
  1611.     button_args[1].value = (XtArgVal)"TLM Log Off";
  1612.     button_args[2].value = (XtArgVal)kissbutton;
  1613.     tlmbutton = XtCreateManagedWidget("tlmButton", commandWidgetClass,
  1614.                 compwindow, button_args, XtNumber(button_args));
  1615.  
  1616.     callback[0].callback = CancelFillCb;
  1617.     callback[0].closure  = toplevel;
  1618.     button_args[0].value = (XtArgVal)callback;
  1619.     button_args[1].value = (XtArgVal)"Cancel Fill";
  1620.     button_args[2].value = (XtArgVal)tlmbutton;
  1621.     cancelbutton = XtCreateManagedWidget("cancelButton", commandWidgetClass,
  1622.                 compwindow, button_args, XtNumber(button_args));
  1623.  
  1624.     callback[0].callback = FillDirectoryCb;
  1625.     callback[0].closure  = toplevel;
  1626.     button_args[0].value = (XtArgVal)callback;
  1627.     button_args[1].value = (XtArgVal)"Fill Directory";
  1628.     button_args[2].value = (XtArgVal)cancelbutton;
  1629.     dirbutton = XtCreateManagedWidget("dirButton", commandWidgetClass,
  1630.                 compwindow, button_args, XtNumber(button_args));
  1631.  
  1632.     callback[0].callback = FillFileCb;
  1633.     callback[0].closure  = toplevel;
  1634.     button_args[0].value = (XtArgVal)callback;
  1635.     button_args[1].value = (XtArgVal)"Fill File";
  1636.     button_args[2].value = (XtArgVal)dirbutton;
  1637.     filebutton = XtCreateManagedWidget("fileButton", commandWidgetClass,
  1638.                 compwindow, button_args, XtNumber(button_args));
  1639.  
  1640.     id[0] = '\0';
  1641.     text_args[0].value = (XtArgVal)filebutton;
  1642.     text_args[1].value = (XtArgVal)resources.text_font;
  1643.     text_args[2].value = (XtArgVal)id;
  1644.     text_args[3].value = (XtArgVal)WhitePixel(dpy, DefaultScreen(dpy));
  1645.     filetext = XtCreateManagedWidget("fileidText", asciiTextWidgetClass,
  1646.                 compwindow, text_args, XtNumber(text_args));
  1647.  
  1648.     label_args[0].value = (XtArgVal)quitbutton;
  1649.     label_args[2].value = (XtArgVal)resources.button_font;
  1650.     totallabel = XtCreateManagedWidget("totalLabel", labelWidgetClass,
  1651.                 compwindow, label_args, XtNumber(label_args));
  1652.  
  1653.     label_args[1].value = (XtArgVal)totallabel;
  1654.     label_args[3].value = (XtArgVal)115;
  1655.     filelabel = XtCreateManagedWidget("fileLabel", labelWidgetClass,
  1656.                 compwindow, label_args, XtNumber(label_args));
  1657.  
  1658.     label_args[1].value = (XtArgVal)filelabel;
  1659.     label_args[3].value = (XtArgVal)110;
  1660.     dirlabel = XtCreateManagedWidget("dirLabel", labelWidgetClass,
  1661.                 compwindow, label_args, XtNumber(label_args));
  1662.  
  1663.     label_args[1].value = (XtArgVal)dirlabel;
  1664.     tlmlabel = XtCreateManagedWidget("tlmLabel", labelWidgetClass,
  1665.                 compwindow, label_args, XtNumber(label_args));
  1666.  
  1667.     label_args[1].value = (XtArgVal)tlmlabel;
  1668.     crclabel = XtCreateManagedWidget("crcLabel", labelWidgetClass,
  1669.                 compwindow, label_args, XtNumber(label_args));
  1670.  
  1671.     window_args[0].value = (XtArgVal)totallabel;
  1672.     window_args[1].value = (XtArgVal)WhitePixel(dpy, DefaultScreen(dpy));
  1673.     window_args[2].value = (XtArgVal)resources.text_font;
  1674.     datawindow = XtCreateManagedWidget("monitorText", asciiTextWidgetClass,
  1675.                 compwindow, window_args, XtNumber(window_args));
  1676.  
  1677.     createMessagePopup(resources.bold_font, resources.button_font);
  1678.  
  1679.     /* initialize the open files structure */
  1680.     for (n = 0; n < MAXFILES; n++)
  1681.     {
  1682.         of[n].fileId    = 0;
  1683.         of[n].file      = NULL;
  1684.         of[n].hdrSeen   = 0;
  1685.         of[n].fileSize  = 0;
  1686.         of[n].holes     = 0;
  1687.         of[n].firstHole = NULL;
  1688.     }
  1689.  
  1690.     /* open up the raw socket to receive all packets */
  1691.     if ((s_raw = socket(AF_INET, SOCK_PACKET, htons(2))) == -1)
  1692.     {
  1693.         perror("socket");
  1694.         return(1);
  1695.     }
  1696.  
  1697.     /* open up the AX25 datagram socket to send file requests */
  1698.     if ((s_file = socket(AF_AX25, SOCK_RAW, PID_FILE)) == -1)
  1699.     {
  1700.         perror("socket");
  1701.         return(1);
  1702.     }
  1703.  
  1704.     if (bind(s_file, (struct sockaddr *)&src, sizeof(src)) == -1)
  1705.     {
  1706.         perror("bind");
  1707.         return(1);
  1708.     }
  1709.  
  1710.     /* open up the AX25 datagram socket to send directory requests */
  1711.     if ((s_directory = socket(AF_AX25, SOCK_RAW, PID_DIRECTORY)) == -1)
  1712.     {
  1713.         perror("socket");
  1714.         return(1);
  1715.     }
  1716.  
  1717.     if (bind(s_directory, (struct sockaddr *)&src, sizeof(src)) == -1)
  1718.     {
  1719.         perror("bind");
  1720.         return(1);
  1721.     }
  1722.  
  1723.     /* we want to be notified whenever a frame is received on the raw socket */
  1724.     XtAppAddInput(app_context, s_raw, (XtPointer)XtInputReadMask, GetFrame, NULL);
  1725.  
  1726.     /* open up a udp socket to receive file fill requests from other apps */
  1727.     memset((char *)&request_addr, 0, sizeof(request_addr));
  1728.     request_addr.sin_family      = AF_INET;
  1729.     request_addr.sin_addr.s_addr = INADDR_ANY;
  1730.     request_addr.sin_port        = htons(5100);
  1731.  
  1732.     if ((s_request = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  1733.     {
  1734.         perror("socket - s_request");
  1735.     }
  1736.     else
  1737.     {
  1738.         XtAppAddInput(app_context, s_request, (XtPointer)XtInputReadMask, FillRequest, NULL);
  1739.     }
  1740.         
  1741.     if (bind(s_request, (struct sockaddr *)&request_addr, sizeof(request_addr)) == -1)
  1742.     {
  1743.         perror("bind - s_request");
  1744.     }
  1745.  
  1746.     UpdateStatus();
  1747.  
  1748.     XtAppAddTimeOut(app_context, TIMEOUT * 1000, TimeoutCb, NULL);
  1749.  
  1750.     XtRealizeWidget(toplevel);
  1751.  
  1752.     XtAppMainLoop(app_context);
  1753.     
  1754.     return(0);
  1755. }
  1756.  
  1757.